﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections;
using System.Reflection;

namespace personalplaner.business
{
	//public class ListBase<T> : List<T>, INotifyPropertyChanged, IFocusMover, IDataErrorInfo//, IItemProperties
	public class ListBase<T> : ObservableCollection<T>, INotifyPropertyChanged, /*IFocusMover,*/ IDataErrorInfo//, IItemProperties
	{
		#region IDataErrorInfo Members

		/// <summary>
		/// Gets an error message indicating what is wrong with this object.
		/// </summary>
		/// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
		public string Error { get; private set; }

		/// <summary>
		/// Gets the error message for the property with the given name.
		/// </summary>
		/// <returns>The error message for the property. The default is an empty string ("").</returns>
		public string this[string property]
		{
			get
			{
				string msg = !string.IsNullOrEmpty(property) ? IsPropertyValid(property) : string.Empty;
				if (string.IsNullOrEmpty(msg))
				{
					this.Error = null;
				}
				else
				{
					this.Error = property;  //Keep track of the most recently validated property that is invalid.
				}
				return msg;
			}
		}

		/// <summary>
		/// Determines whether the specified property is valid.
		/// </summary>
		/// <param name="property">The name of the property.</param>
		/// <returns>if not valid the error message, otherwise null.</returns>
		protected virtual string IsPropertyValid(string property)
		{
			return null;
		}

		List<string> validateProperties;
		private void FillValidateProperties()
		{

			if (validateProperties != null)
				return;


			//get all properties of the instance (properties of child and base class)
			var properties = (from p in this.GetType().GetProperties()
							  where p.DeclaringType != typeof(ItemBase) && p.Name != "DataValue" && p.Name != "Id"
							  select p).ToList();

			validateProperties = (from ia in properties
								  orderby ia.Name
								  select ia.Name).ToList();

			//List<AttributeNameOrder> listItemAttribute = new List<AttributeNameOrder>();
			//var orderPosition = double.MaxValue;

			//foreach (var propertyInfo in properties)
			//{
			//    var customAttributes = propertyInfo.GetCustomAttributes(true).OfType<ItemFocusOrderAttribute>().FirstOrDefault();
			//    if (customAttributes != null)
			//    {
			//        listItemAttribute.Add(new AttributeNameOrder() { Name = propertyInfo.Name, Order = customAttributes.Order });
			//    }
			//    else
			//    {
			//        listItemAttribute.Add(new AttributeNameOrder() { Name = propertyInfo.Name, Order = orderPosition-- });
			//    }
			//}

			//validateProperties = (from ia in listItemAttribute
			//                      where ia.Order > 0.0
			//                      orderby ia.Order
			//                      select ia.Name).ToList();
		}

		/// <summary>
		/// Determines whether this instance is valid.
		/// Properties of this instance (child and base class) will be verified.
		/// </summary>
		/// <returns>
		///   <c>true</c> if this instance is valid; otherwise, <c>false</c>.
		/// </returns>
		public bool IsValid
		{
			get
			{
				this.FillValidateProperties();
				if (validateProperties == null)
				{
					return true;
				}
				else
				{
					return !validateProperties.Any(prop => !string.IsNullOrEmpty(this[prop]));
				}
			}
		}

		#endregion

		#region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

		protected void RaisePropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}

		#endregion

        //#region IFocusMover Members

        //public event EventHandler<MoveFocusEventArgs> MoveFocus;

        //public void RaiseMoveFocus(string focusedProperty)
        //{
        //    if (this.MoveFocus != null)
        //    {
        //        this.MoveFocus(this, new MoveFocusEventArgs(focusedProperty));
        //    }
        //}

        //#endregion

		string _name;
		public virtual string Name
		{
			get
			{
				return _name;
			}
			set
			{
				_name = value;
				RaisePropertyChanged("Name");
			}
		}

		int _id;
		public virtual int ID
		{
			get
			{
				return _id;
			}
			set
			{
				_id = value;
				RaisePropertyChanged("ID");
			}
		}

        /// <summary>
        /// replaces object1 with object2
        /// </summary>
        /// <param name="object1"></param>
        /// <param name="object2"></param>
        public void Replace(T object1, T object2)
        {
            var index = IndexOf(object1);
            Remove(object1);
            Insert(index, object2);
        }

		//#region IItemProperties Members

		//public ReadOnlyCollection<ItemPropertyInfo> ItemProperties
		//{
		//    get { return GetItemProperties(); }
		//}

		//internal ReadOnlyCollection<ItemPropertyInfo> GetItemProperties()
		//{
		//    IEnumerable collection = this;
		//    if (collection == null)
		//        return null;

		//    IEnumerable properties = null;

		//    ITypedList itl = collection as ITypedList;
		//    Type itemType;
		//    object item;

		//    if (itl != null)
		//    {
		//        // ITypedList has the information 
		//        properties = itl.GetItemProperties(null);
		//    }
		//    //else if ((itemType = GetItemType(false)) != null)
		//    //{
		//    //    // If we know the item type, use its properties.
		//    //    properties = TypeDescriptor.GetProperties(itemType);
		//    //}
		//    //else if ((item = GetRepresentativeItem()) != null)
		//    //{
		//    //    // If we have a representative item, use its properties.
		//    //    // It's cheaper to use the item type, but we cannot do that 
		//    //    // when all we know is a representative item.  If the item
		//    //    // has synthetic properties (via ICustomTypeDescriptor or
		//    //    // TypeDescriptorProvider), they don't show up on the type -
		//    //    // only on the item. 
		//    //    properties = TypeDescriptor.GetProperties(item);
		//    //}

		//    if (properties == null)
		//        return null;

		//    // convert the properties to ItemPropertyInfo
		//    List<ItemPropertyInfo> list = new List<ItemPropertyInfo>();
		//    foreach (object property in properties)
		//    {
		//        PropertyDescriptor pd;
		//        PropertyInfo pi;

		//        if ((pd = property as PropertyDescriptor) != null)
		//        {
		//            list.Add(new ItemPropertyInfo(pd.Name, pd.PropertyType, pd));
		//        }
		//        else if ((pi = property as PropertyInfo) != null)
		//        {
		//            list.Add(new ItemPropertyInfo(pi.Name, pi.PropertyType, pi));
		//        }
		//    }

		//    // return the result as a read-only collection
		//    return new ReadOnlyCollection<ItemPropertyInfo>(list);
		//}


		//#endregion
	}
}
